home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / COMM / RPL60 / RPLREP.INC < prev    next >
Text File  |  1992-12-31  |  13KB  |  339 lines

  1.  
  2.   {*}
  3.   {*source code copyright (c) 1985, by TurboPower Software*}
  4.   {*}
  5.   {*}
  6.  
  7.  
  8.   function GetRep(var arg : PatLine; var PatList : PatPtr) : Boolean;
  9.     {-convert argument into a pattern list, pointed to by patlist}
  10.     {return true if successful}
  11.  
  12.     function MakeRep(var arg : PatLine; Start : Integer; Delim : Char; var PatList : PatPtr) : Integer;
  13.       {-make a pattern list from arg[i], starting at start, ending at delim}
  14.       {return 0 is error, last char position in arg if OK}
  15.     var
  16.       i              : Integer;
  17.       Lastj, j       : PatPtr;
  18.       Done           : Boolean;
  19.       c              : Char;
  20.  
  21.       procedure AddRep(Tok : Tokens; Lastj : PatPtr; var j : PatPtr; s : LongString);
  22.         {-add a token record to the pattern list}
  23.         {s contains a literal character or an expanded character class}
  24.       begin
  25.         New(j);                   {allocate a new pointer for this token}
  26.         j^.Tok := Tok;            {save token type}
  27.         j^.NexTok := False;       {default to non-alternation}
  28.         j^.NestPtr := nil;        {nestptr and next are filled in later if at all}
  29.         j^.Next := nil;
  30.         Lastj^.Next := j;         {hook up the previous token}
  31.         if (Tok = tLitChar) or (Tok = tDitto) then begin
  32.           j^.One := s[1];
  33.           j^.StrPtr := nil;
  34.         end else begin
  35.           WrL('addrep:can''t happen');
  36.           Halt;
  37.         end;
  38.       end;                        {addrep}
  39.  
  40.     begin                         {makerep}
  41.       New(PatList);               {starter point for patlist}
  42.       PatList^.Tok := tNil;       {put a nil token at the beginning}
  43.       PatList^.NexTok := False;
  44.       PatList^.Next := nil;       {terminate list in case of nil pattern}
  45.       Lastj := PatList;
  46.       i := Start;                 {start point of pattern string}
  47.       Done := False;
  48.       while not(Done) and (arg[i] <> Delim) and (arg[i] <> EndStr) do begin
  49.         c := arg[i];
  50.         if (c = Ditto) then
  51.           AddRep(tDitto, Lastj, j, '0')
  52.         else begin
  53.           if c = Esc then begin
  54.             {skip over escape character}
  55.             i := Succ(i);
  56.             c := arg[i];
  57.             if (c >= '1') and (c <= '9') then
  58.               {a tagged ditto}
  59.               AddRep(tDitto, Lastj, j, c)
  60.             else case c of
  61.               lSpace : AddRep(tLitChar, Lastj, j, #32);
  62.               lNewline : begin
  63.                            AddRep(tLitChar, Lastj, j, #13);
  64.                            Lastj := j;
  65.                            AddRep(tLitChar, Lastj, j, #10);
  66.                          end;
  67.               lTab : AddRep(tLitChar, Lastj, j, #9);
  68.               lBackSpace : AddRep(tLitChar, Lastj, j, #8);
  69.               lReturn : AddRep(tLitChar, Lastj, j, #13);
  70.               lFeed : AddRep(tLitChar, Lastj, j, #10);
  71.               lInput : AddRep(tLitChar, Lastj, j, #60);
  72.               lOutput : AddRep(tLitChar, Lastj, j, #62);
  73.               lPipe : AddRep(tLitChar, Lastj, j, #124);
  74.               lNil : ;
  75.             else
  76.               AddRep(tLitChar, Lastj, j, c);
  77.             end;
  78.           end else
  79.             AddRep(tLitChar, Lastj, j, c);
  80.         end;
  81.         Lastj := j;
  82.         if not(Done) then i := Succ(i);
  83.       end;                        {of looking through pattern string}
  84.       if Done or (arg[i] <> Delim) then begin
  85.         MakeRep := 0;
  86.         WrL('pattern error detected near end of '+Copy(arg, 1, i));
  87.       end else MakeRep := i;
  88.     end;                          {makerep}
  89.  
  90.   begin                           {getrep}
  91.     GetRep := (MakeRep(arg, 1, EndStr, PatList) > 0);
  92.   end;                            {getrep}
  93.  
  94.   procedure SubLine(var Lin : Line; PatRec, RepRec : PatPtr; var Sub : Line);
  95.     {-rescan the line to get flags and multiple substititions}
  96.   var
  97.     NumToAdd, TagNum, i, Lastm, m : Integer;
  98.     tSub           : Line;
  99.     flags          : Flag;
  100.     TagOn, DidReplace : Boolean;
  101.  
  102.     function aMatch(var Lin : Line; var flags : Flag;
  103.                     OffSet         : Integer;
  104.                     var TagNum     : Integer;
  105.                     Pat            : PatPtr) : Integer;
  106.       {-look for match of pattern list starting at pat with lin.val[offset...]}
  107.       {return the last position that matched}
  108.     var
  109.       i, k, LocTag   : Integer;
  110.       j              : PatPtr;
  111.       Done, Junk     : Boolean;
  112.       tTok           : Tokens;
  113.  
  114.       function oMatch(var Lin : Line; var flags : Flag;
  115.                       var i, TagNum  : Integer;
  116.                       Pat            : PatPtr) : Boolean;
  117.         {-match one pattern element at pattern pointed to by pat, lin.val[i]}
  118.       var
  119.         Advance        : -1..255;
  120.         tTok           : Tokens;
  121.         k              : Integer;
  122.         c              : Char;
  123.       begin                       {omatch}
  124.         Advance := -1;
  125.         tTok := Pat^.Tok;
  126.           if IgnoreCase then c := UpCaseMac(Lin.Val[i]) else c := Lin.Val[i];
  127.  
  128.         if c <> EndStr then begin
  129.           if tTok = tLitChar then begin
  130.             if c = Pat^.One then Advance := 1;
  131.           end else if tTok = tCcl then begin
  132.             k := Pos(c, Pat^.StrPtr^);
  133.             if k > 0 then Advance := 1;
  134.           end else if tTok = tnCcl then begin
  135.             if Pos(c, NewLine) = 0 then begin
  136.               k := Pos(c, Pat^.StrPtr^);
  137.               if k = 0 then Advance := 1;
  138.             end;
  139.           end else if tTok = tAny then begin
  140.             if (c <> #13) and (c <> #10) then Advance := 1;
  141.           end else if tTok = tBol then begin
  142.             if i = 1 then Advance := 0;
  143.           end else if tTok = tEol then begin
  144.             if (c = #13) and (Lin.Val[Succ(i)] = #10) then begin
  145.               Advance := 0;
  146.             end;
  147.           end else if tTok = tNil then begin
  148.             Advance := 0;
  149.           end else if tTok = tbTag then begin
  150.             Advance := 0;
  151.             if not(TagOn) then begin
  152.               {WrL('increment tagnum to ',tagnum+1);}
  153.               TagNum := Succ(TagNum);
  154.               TagOn := True;
  155.             end;
  156.           end else if tTok = teTag then begin
  157.             Advance := 0;
  158.             TagOn := False;
  159.           end else if tTok = tGroup then begin
  160.             {we treat a group as a "character", but allow advance of multiple chars}
  161.             {recursive call to amatch}
  162.             k := aMatch(Lin, flags, i, TagNum, Pat^.NestPtr);
  163.             if k >= i then begin
  164.               i := k;
  165.               Advance := 0;
  166.             end;
  167.           end;
  168.         end else begin
  169.           {at end of line}
  170.           {end tag marks match}
  171.           if (tTok = teTag) then Advance := 0;
  172.         end;
  173.  
  174.         if Advance > 0 then begin
  175.           {we had a match at this (these) character position(s)}
  176.           {set the match flags}
  177.             if TagOn then flags[i] := TagNum else flags[i] := 0;
  178.           i := i+Advance;
  179.           oMatch := True;
  180.         end else if Advance = 0 then begin
  181.           oMatch := True;
  182.         end else begin
  183.           {this character didn't match}
  184.           oMatch := False;
  185.           flags[i] := -1;
  186.         end;
  187.       end;                        {omatch}
  188.  
  189.     begin                         {amatch}
  190.       Done := False;
  191.       j := Pat;
  192.       while not(Done) and (j <> nil) do begin
  193.         tTok := j^.Tok;
  194.         if tTok = tClosure then begin
  195.           {a closure}
  196.           j := j^.Next;           {step past the closure in the pattern list}
  197.           i := OffSet;            {leave the current line position unchanged}
  198.           LocTag := TagNum;
  199.           {match as many as possible}
  200.           while not(Done) and (Lin.Val[i] <> EndStr) do begin
  201.             if not(oMatch(Lin, flags, i, LocTag, j)) then Done := True;
  202.           end;
  203.           {i points to the location that caused a non-match}
  204.           {match rest of pattern against rest of input}
  205.           {shrink closure by one after each failure}
  206.           Done := False;
  207.           while not(Done) and (i >= OffSet) do begin
  208.             {call amatch recursively}
  209.             k := aMatch(Lin, flags, i, LocTag, j^.Next);
  210.             if k > 0 then
  211.               Done := True
  212.             else begin
  213.               i := Pred(i);
  214.               LocTag := flags[i];
  215.               {WrL('resetting tagnum to ',loctag);}
  216.             end;
  217.           end;
  218.           OffSet := k;            {if k=0 then failure else success}
  219.           TagNum := LocTag;
  220.           Done := True;
  221.         end else if tTok = tMaybeOne then begin
  222.           {a 0 or 1 closure}
  223.           j := j^.Next;           {step past the closure marker}
  224.           {match or no match is ok, but advance lin cursor if matched}
  225.           Junk := oMatch(Lin, flags, OffSet, TagNum, j);
  226.           {advance to the next pattern token}
  227.           j := j^.Next;
  228.         end else if not(oMatch(Lin, flags, OffSet, TagNum, j)) then begin
  229.           if j^.NexTok then begin
  230.             {we get another chance because of alternation}
  231.             j := j^.Next;
  232.           end else begin
  233.             {omatch failed, can't back up}
  234.             OffSet := 0;
  235.             Done := True;
  236.           end;
  237.         end else begin            {omatch succeeded}
  238.           {skip over alternates if we matched already}
  239.           while j^.NexTok and (j^.Next <> nil) do j := j^.Next;
  240.           {move to the next non-alternate}
  241.           j := j^.Next;
  242.         end;
  243.       end;
  244.       aMatch := OffSet;
  245.     end;                          {amatch}
  246.  
  247.     procedure WriteSub(var Lin : Line; var flags : Flag; RepRec : PatPtr;
  248.                        i, iEnd : Integer; var m : Line);
  249.       {-Wr the output line with replacements}
  250.     var
  251.       TagNum, iStart, iStop : Integer;
  252.       j              : PatPtr;
  253.       Tok            : Tokens;
  254.  
  255.       function FindTag(var Lin : Line; var flags : Flag; i, iEnd, TagNum : Integer;
  256.                        {-} var iStart, iStop : Integer) : Boolean;
  257.         {-find the tagged match region}
  258.         {return true if it is found}
  259.       begin
  260.         iStart := i;
  261.         while (Lin.Val[iStart] <> EndStr) and (flags[iStart] <> TagNum) do
  262.           iStart := Succ(iStart);
  263.         if flags[iStart] = TagNum then begin
  264.           FindTag := True;
  265.           iStop := iStart;
  266.           while (flags[iStop] = TagNum) and (iStop < iEnd) do
  267.             iStop := Succ(iStop);
  268.         end else FindTag := False;
  269.       end;                        {findtag}
  270.  
  271.     begin                         {writesub}
  272.       {scan the replacement list}
  273.       m.Length := 0;
  274.       j := RepRec;
  275.       while j <> nil do begin
  276.         Tok := j^.Tok;
  277.         if Tok = tDitto then begin
  278.           TagNum := Ord(j^.One)-Ord('0');
  279.           if TagNum = 0 then begin
  280.             {untagged ditto}
  281.             {add the entire matched region}
  282.             AppendS(m.Val[1], m.Length, Lin.Val[i], iEnd-i, m);
  283.           end else begin
  284.             {tagged ditto}
  285.             {find the tagged region}
  286.             if FindTag(Lin, flags, i, iEnd, TagNum, iStart, iStop) then begin
  287.               {add the tagged region}
  288.               AppendS(m.Val[1], m.Length, Lin.Val[iStart], iStop-iStart, m);
  289.             end                   {else couldn't find tagged word, don't append anything}
  290.             else begin
  291.             end;
  292.           end;
  293.         end else if Tok = tLitChar then
  294.           AppendS(m.Val[1], m.Length, j^.One, 1, m);
  295.         j := j^.Next;
  296.       end;
  297.     end;                          {writesub}
  298.  
  299.     { I debug.inc}
  300.  
  301.   begin
  302.     DidReplace := False;
  303.     Lastm := 0;
  304.     i := 1;
  305.  
  306.     {m:=lin.length;}
  307.     {debug(false);}
  308.  
  309.     Sub.Length := 0;
  310.     while (Lin.Val[i] <> EndStr) do begin
  311.       TagNum := 0;
  312.       TagOn := False;
  313.  
  314.       m := aMatch(Lin, flags, i, TagNum, PatRec);
  315.  
  316.       if (m > 0) and (m <> i) and (Lastm <> m) then begin
  317.         {keep track of count}
  318.         DidReplace := True;
  319.         if wrCnt < 32766 then wrCnt := Succ(wrCnt);
  320.         {debug(true);}
  321.         {replace matched text}
  322.         WriteSub(Lin, flags, RepRec, i, m, tSub);
  323.         Lastm := m;
  324.         AppendS(Sub.Val[1], Sub.Length, tSub.Val[1], tSub.Length, Sub);
  325.       end;
  326.  
  327.       if (m = 0) or (m = i) then begin
  328.         {no match or null match, append the character}
  329.           if Lin.Val[i] = #13 then NumToAdd := 2 else NumToAdd := 1;
  330.         AppendS(Sub.Val[1], Sub.Length, Lin.Val[i], NumToAdd, Sub);
  331.         i := i+NumToAdd;
  332.       end else                    {skip matched text}
  333.         i := m;
  334.  
  335.     end;
  336.     if DidReplace then MatchCnt := Succ(MatchCnt);
  337.   end;                            {subline}
  338.  
  339.